#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#include "pub_lib.h"

void UpdateProgress(float progress)
{
	int barWidth = 70;

	printf("[");
	int pos = barWidth * progress;
	for (int i = 0; i < barWidth; ++i)
	{
		if (i < pos)
			printf("=");
		else if (i == pos)
			printf(">");
		else
			printf(" ");
	}
	printf("] %d\r", (int)(progress * 100.0));
	fflush(stdout);
}

void get_full_path(char* path, char* file_name, char* full)
{
	sprintf(full, "%s%s", path, file_name);
}

/* x，y 值最大只能是 max
 * 如果不是，则计算出新的newx, newy
 * 保证 newx，newy 最大只能是max，
 * 并且是等比例变换
 * */
void cal_scaled_val(int max, int x, int y, int *xnew, int *ynew)
{
	int width_flag = 0;
	int neww = x, newh = y;

	int maxv = y;
	if (x > y) {
		maxv = x;
		width_flag = 1;
	}

	if (width_flag) {
		neww = max;
		newh = neww * y / x;
	} else {
		newh = max;
		neww = newh * x / y;
	}
	*xnew = neww;
	*ynew = newh;
}

int get_radix2_value(int value)
{
	float v;
	int a;
	v = log2f(value);
	a = (int)v;
	v = powf(2.0f, a);
	return (int)(v);
}

void cal_scaled_val_radix2(int max, int x, int y, int* xnew, int* ynew)
{
	max = get_radix2_value(max);
	cal_scaled_val(max, x, y, xnew, ynew);
}

/*
 * 左边小图：占据宽度的30%, 右边大图：占据宽度的70%
 * 这里取整，返回取整后的最大宽度
 * */
int get_max_pixel(int width, float percent)
{
	int ret, temp;
	ret = width * percent;
	temp = ret % 100;
	ret -= temp;
	return ret;
}


/* 右边的窗口分为2半 
 * 返回取整后的最大宽度 */
int split_right_window(int width, float percent)
{
	int ret, temp;
	ret = width * percent;
	temp = ret % 10;
	ret -= temp;

	ret = (ret - 30) / 2;
	return ret;
}

//how many bytes of one pixel occupy
//w: image width, h: image height
int get_pixel_bytes(int w, int h, int image_size)
{
	int ret;
	ret = image_size / w / h;
	return ret;
}

Color makeRGBA(void* r)
{
	unsigned char* d = (unsigned char*)r;
	Color c = {*d, *(d+1), *(d+2), 255};
	return c;
}

/*
 * 窗口坐标下的索引值
 * width: 窗口的宽度
 * x: 第几列，从0开始
 * y: 第几行，从0开始
 * */
int get_window_index(int y, int x, int width)
{
	return (y * width + x);
}

/*
 *  line_bytes: 一行的像素一共有多少字节
 *  从原始图像的缓存中得到索引值
 *  width: 图片的宽度
 * */
int get_image_index(int y, int x, int width, int pix_len)
{
	int index = get_window_index(y, x, width);
	index *= pix_len;
	return index;
}

void reset_frame_buf(Color* frame_buf, int len, Color c)
{
	int i;
	for(i = 0; i < len; i++) {
		frame_buf[i] = c;
	}
}

//clear rectangle area
void clear_fb_range(Color* frame_buf, int fb_width,\
	int startx, int starty,\
	int endx, int endy, Color c)
{
	int x, y, index;
	for (y = starty; y <= endy; y++) {
		for (x = startx; x <= endx; x++) {
			index = get_window_index(y, x, fb_width);
			frame_buf[index] = c;
		}
	}
}

/* CPU render 
 * width, height: screen width, height
 * */
void draw_image(Color* frame_buf, int width, int height)
{
	int x, y, index;

	for(y = 0; y < height; y++) {
		for ( x = 0; x < width; x++) {
			index = get_window_index(y, x, width);
			if (sampled_point(frame_buf[index])) {
				DrawPixel(x, y, frame_buf[index]);
			}
		}
	}
}

void show_ori_image(cpu_image* ptr, int startx, int starty)
{
	//fill framebuf
	int x, y, index, indexW;
	Color c;
	char* src = (char*)ptr; //point to original image data

	for (y = 0; y < ptr->image_height; y++) {
		for (x = 0; x < ptr->image_width; x++) {
			index = get_image_index(y, x, ptr->image_width, ptr->pix_len);
			c = makeRGBA((void*)(src + index));
			indexW = get_window_index(y + starty, x + startx, ptr->win_width);
			ptr->frame_buf[indexW] = c;
		}
	}
}

void print_info_cn(const char ary[][MAX_HINT_STRING_LEN], int n)
{
	int i;

	printf("pleasse input number 1 - %d: \n", n);
	for( i = 0; i < n; i++)
		printf("%s\n", ary[i]);
	printf("\n");
}

void show_info_en(const char ary[][MAX_HINT_STRING_LEN], int n, int x, int y)
{
	int height = 20;
	int off = height + 10;
	Color c = BLACK;
	int i;

	for(i = 0; i < n; i++) {
		DrawText(TextFormat("%s", ary[i]), x, y, height, c);
		y += off;
	}
}

void draw_histogram(Color* frame_buf, int fb_width, \
	int startx, int starty, \
	int endx, int endy, unsigned int* histo)
{
	int w = endx - startx;
	int h = endy - starty;
	DrawRectangleLines(startx, starty, w, h, BLACK);

	//第一遍扫描，找到极值
	unsigned int max, min;
	int i;
	max = 0;
	min = 0xffffffff;
	for (i = 0; i < 256; i++) {
		if (histo[i] < min)
			min = histo[i];
		if (histo[i] > max)
			max = histo[i];
	}
	//(histo[i] - min) * h / (max - min)
	float xunit = (float)w / 257.0f;
	unsigned int xco, yco;
	int y = starty + h;
	for (i = 0; i < 256; i++) {
		xco = startx + (i + 1) * xunit;
		if (histo[i]) {
			yco = (histo[i] - min) * h / (max - min) ;
			DrawLine(xco, y, xco, y - yco, BLACK);
		}
	}
}

/* 画出直方图的变换函数 */
void draw_his_trans_func(Color* frame_buf, int fb_width, \
	int startx, int starty, \
	int endx, int endy, unsigned char* sk)
{
	int y, i;
	int w = endx - startx;
	int h = endy - starty;

	DrawRectangleLines(startx, starty, w, h, BLACK);
	unsigned int xco, yco;
	float xunit = (float)w / 257.0f;
	int first = 1;
	y = starty + h;

	for (i = 0; i < 256; i++) {
		xco = startx + (i + 1) * xunit;
		if (sk[i]) {
			yco = sk[i] * h / 255;
			yco = starty + h - yco;
			DrawPixel(xco, yco, BLACK);
			if(first) {
				first = 0;
				DrawLine(xco, y, xco, yco, BLACK);
			} else {
				DrawPixel(xco, yco, BLACK);
			}
		}
	}
}

void print_histo_data(unsigned int* histo)
{
	int i;
	for (i = 0; i < 256; i++)
		printf("%.3d: %d\n", i, histo[i]);
}

#define K1 0.002
#define A1 1
#define A2 0.07
#define U1 0.15
#define SIG1 0.05
#define U2 0.75
#define SIG2 0.05
#define pi 3.1415626535627

//双峰值高斯函数
/*
 * 以下系数由Matlab R2022a 生成
 * res/fit_two_Gaussians.m: matlab源代码
 *
coefficients =
          5.94927398063884
        -0.009857834374856
          100.224153670984
          10.0172874361468
          100.915290601432
          9.83841307956237
           199.75473328304
          10.4387922278488
   Y = a + b*x + c*exp(-(x-d)^2/e) + c1 * exp(-(x-f)^2/g)
*/
double twoModeGauss(double x)
{
	double a = 5.94927398063884;
	double b = -0.009857834374856;
	double c = 100.224153670984;;
	double d = 10.0172874361468;
	double e = 100.915290601432;
	double c1 = 9.83841307956237;
	double f = 199.75473328304;
	double g = 10.4387922278488;

	double ret;
	ret = a + b * x;;
	ret = ret + c * exp(-(pow((x - d), 2)/e));
	ret = ret + c1 * exp(-(pow((x - f), 2)/g));
	return ret;
}


/* fill image
 * float image[h][w]
 * char  ori[ori_h][ori_w]
 * */
void fill_zero_char(float* image, int w, int h,\
	char* ori, int ori_w, int ori_h)
{
	int i, j;
	for(i = 0; i < (w * h); i++)
		image[i] = 0;

	for(j = 0; j < ori_h; j++) {
		for(i = 0; i < ori_w; i++) {
			image[j * w + i] = ori[j * ori_w + i];
		}
	}
}

void fill_zero_byte(float* image, int w, int h,\
	unsigned char* ori, int ori_w, int ori_h)
{
	int i, j;
	for(i = 0; i < (w * h); i++)
		image[i] = 0;

	for(j = 0; j < ori_h; j++) {
		for(i = 0; i < ori_w; i++) {
			image[j * w + i] = ori[j * ori_w + i];
		}
	}
}


/* fill image
 * float image[h][w]
 * float  ori[ori_h][ori_w]
 * */
void fill_zero_float(float* image, int w, int h,\
	float* ori, int ori_w, int ori_h)
{
	int i, j;
	for(i = 0; i < (w * h); i++)
		image[i] = 0;

	for(j = 0; j < ori_h; j++) {
		for(i = 0; i < ori_w; i++) {
			image[j * w + i] = ori[j * ori_w + i];
		}
	}
}

void scale_int_data(unsigned int *data, unsigned char *out, int size)
{
	unsigned int min, max;
	min = -1;
	max = 0;
	//get min max
	int i;
	for(i = 0; i < size; i++) {
		if(data[i] < min)
			min = data[i];
		if(data[i] > max)
			max = data[i];
	}
	printf("scale_int_data: data[0]=%d, min=%d,max=%d\n", data[0], min, max);

	unsigned int diff = max - min;
	for(i = 0; i < size; i++) {
		out[i] = (data[i] - min) * 255 / diff;
	}
}

void scale_int_datai(int* data, unsigned char* out, int size)
{
	int min, max;
	min = 255;
	max = -255;
	//get min max
	int i;
	for (i = 0; i < size; i++) {
		if (data[i] < min)
			min = data[i];
		if (data[i] > max)
			max = data[i];
	}

	unsigned int diff = max - min;
	for (i = 0; i < size; i++) {
		out[i] = (data[i] - min) * 255 / diff;
	}
}

void scale_float_data(float* data, unsigned char* out, int size)
{
	float min, max;
	min = -1;
	max = 0;
	//get min max
	int i;
	for (i = 0; i < size; i++) {
		if (data[i] < min)
			min = data[i];
		if (data[i] > max)
			max = data[i];
	}
	printf("scale_float_data: min=%f,max=%f\n", min, max);

	float diff = max - min;
	for (i = 0; i < size; i++) {
		out[i] = (data[i] - min) * 255 / diff;
	}
}

//log(1 + data[i])
void log_float_data(float *data, unsigned char *out, int size)
{
	float value, min, max;
	min = 0;
	max = 0;

	float* logdata = malloc(size * sizeof(float));
	//get min max
	int i;
	for(i = 0; i < size; i++) {
		value = log10f(data[i] + 1);
		logdata[i] = value;
		if(value < min)
			min = value;
		if(value > max)
			max = value;
	}
	printf("log_float_data: min=%f, max=%f\n", min, max);
	//value = 255 * (v - min) / (max - min);
	for (i = 0; i < size; i++) {
		out[i] = 255.0f * (logdata[i] - min) / (max - min);
	}

	free(logdata);
}



//image[Q][P] to cut_image[h][w]
void restore_ori_image(float* image, int P, int Q,
	float* cut_image, int w, int h)
{
	int i, j;
	for(j = 0; j < h; j++) {
		for(i = 0; i < w; i++) {
			cut_image[j * w + i] = image[j * P + i];
		}
	}
}

// unsigned char data[size]
float data_get_avg(unsigned char* data, int size)
{
	int i;
	float total = 0;
	for(i = 0; i < size; i++)
		total += data[i];
	return (total / size);
}

// unsigned char data[size]
// get sigma^2
float data_get_sigma2(unsigned char* data, int size, float avg)
{
	int i;
	float total = 0;
	for(i = 0; i < size; i++)
		total += ((data[i] - avg) * (data[i] - avg));
	total = total / size;
	return total;
}





